package com.xxx.article.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxx.article.client.NoticeClient;
import com.xxx.article.domain.Article;
import com.xxx.article.domain.Notice;
import com.xxx.article.domain.NoticeFresh;
import com.xxx.article.mapper.ArticleMapper;
import com.xxx.article.service.ArticleService;
import com.xxx.entity.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author blijojo
 */
@Service
@Slf4j
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>
        implements ArticleService {

    private final ArticleMapper articleMapper;

    private final RedisTemplate<String, String> redisTemplate;

    private final NoticeClient noticeClient;

    private final RabbitTemplate rabbitTemplate;

    public ArticleServiceImpl(RedisTemplate<String, String> redisTemplate, ArticleMapper articleMapper, NoticeClient noticeClient, RabbitTemplate rabbitTemplate) {
        this.redisTemplate = redisTemplate;
        this.articleMapper = articleMapper;
        this.noticeClient = noticeClient;
        this.rabbitTemplate = rabbitTemplate;
    }

    @Override
    public Boolean subscribe(String articleId, String userId) {
        //根据文章id查询文章作者id
        String authorId = articleMapper.findUserIdById(articleId);
        //整合rabbitmq,订阅绑定队列与交换机,取消订阅解绑队列与交换机
        RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitTemplate.getConnectionFactory());
        DirectExchange exchange = new DirectExchange("article_subscribe", true, false);
        rabbitAdmin.declareExchange(exchange);
        Queue queue = new Queue("article_subscribe_" + userId, true);
        Binding binding = BindingBuilder.bind(queue).to(exchange).with(authorId);
        //定义用户订阅集合key,存放作者id
        String userKey = "article_subscribe_" + userId;
        //定义作者粉丝集合key,存放粉丝id
        String authorKey = "article_author_" + authorId;
        //查询用户订阅集合,判断是否已经订阅该作者
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        Boolean flag = redisTemplate.opsForSet().isMember(userKey, authorId);
        if (flag != null) {
            //订阅过:删除订阅集合和粉丝集合中的相关id,取消订阅,返回false
            if (flag) {
                redisTemplate.opsForSet().remove(userKey, authorId);
                redisTemplate.opsForSet().remove(authorKey, userId);
                //解绑队列与交换机
                rabbitAdmin.removeBinding(binding);
                //如果用户文章订阅集合为空,删除队列
                if (redisTemplate.opsForSet().size(userKey) <= 0) {
                    rabbitAdmin.deleteQueue("article_subscribe_" + userId);
                }
                return false;
            }
        }
        //flag为null 或者flag为false,执行下面新增操作
        //没订阅过:新增订阅集合和粉丝集合中的相关id,返回true
        redisTemplate.opsForSet().add(userKey, authorId);
        redisTemplate.opsForSet().add(authorKey, userId);
        //绑定队列与交换机
        rabbitAdmin.declareQueue(queue);
        rabbitAdmin.declareBinding(binding);
        return true;

    }

    @Override
    public void add(Article article) {
        //0.获取当前登录用户id,即文章作者id
        //伪代码,实际使用jwt鉴权获取id
        String authorId = "4";
        //1.新增文章
        //1.1 初始化数据
        article.setVisits(0);
        article.setThumbUp(0);
        article.setComment(0);
        article.setCreateTime(new Date());
        article.setUserId(authorId);
        articleMapper.insert(article);
        //2.新增推送通知
        //2.1 获取作者的粉丝id
        String authorKey = "article_author_" + authorId;
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        Set<String> set = redisTemplate.opsForSet().members(authorKey);
        log.info("set ===> {}", set);
        //2.2 遍历粉丝集合,挨个创建通知
        Notice notice;
        if (set != null && set.size() > 0) {
            for (String receiverId : set) {
                notice = new Notice();
                notice.setReceiverId(receiverId);
                notice.setOperatorId(authorId);
                notice.setAction("publish");
                notice.setTargetType("article");
                notice.setTargetId(article.getId());
                notice.setType("user");
                noticeClient.save(notice);
            }
        }
        //3.发送消息提醒到rabbitmq,路由键为作者id,消息内容为文章id
        rabbitTemplate.convertAndSend("article_subscribe", authorId, article.getId());
    }

    @Override
    public boolean thumbup(String articleId, String userId) {
        //获取文章的点赞数
        Article article = articleMapper.selectById(articleId);

        //从redis获取该用户是否点过赞, flag != null:点赞过, flag == null:没点过
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        //定义文章点赞key:包含用户id与被点赞的文章id
        String key = "thumbup_article_" + userId + "_" + articleId;
        String flag = redisTemplate.opsForValue().get(key);
        if (flag == null) {
            //没点过赞,更新thumbUp字段 +1
            article.setThumbUp(article.getThumbUp() + 1);
            articleMapper.updateById(article);
            //并把点赞状态保存入redis
            redisTemplate.opsForValue().set(key, "1");
            //创建点赞通知给作者
            Notice notice = new Notice();
            notice.setReceiverId(article.getUserId());
            notice.setOperatorId(userId);
            notice.setAction("thumbUp");
            notice.setTargetType("article");
            notice.setTargetId(articleId);
            notice.setType("user");
            noticeClient.save(notice);
            return true;
        } else {
            //flag != null,该评论点赞数-1,并删除该用户已点赞状态
            article.setThumbUp(article.getThumbUp() - 1);
            articleMapper.updateById(article);
            redisTemplate.delete(key);
            //删除点赞通知
            Map<String, Object> map = new HashMap<>(4);
            map.put("targetId", articleId);
            map.put("operatorId", userId);
            //根据文章id和点赞者id 查询出通知对象
            Result result = noticeClient.findByCondition(map);
            //如果查询到的通知存在
            if (result.getData() != null) {
                HashMap notice = (HashMap) result.getData();
                //根据通知id删除通知
                noticeClient.deleteById(notice.get("id").toString());
                //再根据 通知id 和 文章作者id 删除待推送通知
                NoticeFresh noticeFresh = new NoticeFresh(article.getUserId(), notice.get("id").toString());
                noticeClient.deleteFresh(noticeFresh);
            }
            return false;
        }

    }
}
